package com.meme.editor.level;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;

import org.apache.log4j.Logger;


import com.meme.editor.EntityObject;
import com.meme.editor.EntityRefLink;
import com.meme.editor.PropertyValueModification;
import com.meme.editor.PropertyValueModificationList;

import com.meme.editor.level.define.ActorDefine;
import com.meme.editor.level.define.ActorTemplate;
import com.meme.editor.level.define.PropertyDefine;
import com.meme.editor.level.define.PropertyDefineBlock;
import com.meme.editor.property.Property;
import com.meme.editor.property.PropertyFactory;
import com.meme.editor.property.PropertyGroupSet;


public class Actor extends EntityObject
{
	static Logger logger = Logger.getLogger(Actor.class);

	
	public static final int SelectedState_NotSelected = 0;
	public static final int SelectedState_RegionSelected = 1;
	public static final int SelectedState_SpecialSelected = 2;
	
	
	public final static String GroupName_ActorGroup = "Actor Properties";
	public final static String PropertyName_PosX        = "Pos X";
	public final static String PropertyName_PosY        = "Pos Y";
	public final static String PropertyName_ZOrder        = "Z Order";
//	public final static String PropertyName_FlipX        = "Flip X";
//	public final static String PropertyName_FlipY        = "Flip Y";
	public final static String PropertyName_ScaleX        = "Scale X";
	public final static String PropertyName_ScaleY        = "Scale Y";
	public final static String PropertyName_Angle        = "Angle";

	
	
	int mPosX;
	int mPosY;
	int mZOrder;
	
	//boolean mFlipX;
	//boolean mFlipY;
	
	double mRotation;
	float mAngle;
	float mScaleX;
	float mScaleY;
	
	int mSelectedState;
	
	//ActorTemplate mActorTemplate;
	EntityRefLink mRefedActorTemplate;
	
	List<Appearance> mAppearanceList = new Vector<Appearance> (3);
	
	public Actor ()
	{
		this (null);
	}
	
	public Actor (String name)
	{
		super (name);
		
		mRefedActorTemplate = new EntityRefLink (this);
		
		createPropertyGroup (GroupName_ActorGroup);
		createPublicProperty (GroupName_ActorGroup, PropertyName_PosX, PropertyFactory.ValueType_Number);
		createPublicProperty (GroupName_ActorGroup, PropertyName_PosY, PropertyFactory.ValueType_Number);
		createPublicProperty (GroupName_ActorGroup, PropertyName_ZOrder, PropertyFactory.ValueType_Number);
//		createPublicProperty (GroupName_ActorGroup, PropertyName_FlipX, PropertyFactory.ValueType_Boolean);
//		createPublicProperty (GroupName_ActorGroup, PropertyName_FlipY, PropertyFactory.ValueType_Boolean);
		createPublicProperty (GroupName_ActorGroup, PropertyName_ScaleX, PropertyFactory.ValueType_Number);
		createPublicProperty (GroupName_ActorGroup, PropertyName_ScaleY, PropertyFactory.ValueType_Number);
		createPublicProperty (GroupName_ActorGroup, PropertyName_Angle, PropertyFactory.ValueType_Number);
		
		
		setScaleX (1.0f);
		setScaleY (1.0f);
		
	}
	
	@Override
	protected void _handleModifyingPropertyValues (PropertyValueModificationList modications)
	{			
		super._handleModifyingPropertyValues (modications);
		
		ListIterator<PropertyValueModification> iter = modications.listIterator();
		while ( iter.hasNext() )
		{
			PropertyValueModification mod = iter.next();
			
			if ( mod.mGroupName.equals (GroupName_ActorGroup) )
			{
				boolean handled = true;
				if ( mod.mPropertyName.equals (PropertyName_PosX) )
				{
					setPosX (( (Float) (mod.mNewValue) ).intValue());
				}
				else if ( mod.mPropertyName.equals (PropertyName_PosY) )
				{
					setPosY (( (Float) (mod.mNewValue) ).intValue());
				}
				else if ( mod.mPropertyName.equals (PropertyName_ZOrder) )
				{
					setZOrder (( (Float) (mod.mNewValue) ).intValue());
				}
//				else if ( mod.mPropertyName.equals (PropertyName_FlipX) )
//				{
//					setFlipX (( (Boolean) (mod.mNewValue) ).booleanValue());
//				}
//				else if ( mod.mPropertyName.equals (PropertyName_FlipY) )
//				{
//					setFlipY (( (Boolean) (mod.mNewValue) ).booleanValue());
//				}
				else if ( mod.mPropertyName.equals (PropertyName_Angle) )
				{
					setAngle (( (Float) (mod.mNewValue) ).intValue());
				}
				else if ( mod.mPropertyName.equals (PropertyName_ScaleX) )
				{
					setScaleX (( (Float) (mod.mNewValue) ).floatValue());
				}
				else if ( mod.mPropertyName.equals (PropertyName_ScaleY) )
				{
					setScaleY (( (Float) (mod.mNewValue) ).floatValue());
				}
				else
					handled = false;
				
				if (handled)
					iter.remove();
			}
		}
	}		
	
	
	public void setActorTemplate (ActorTemplate actorTemplate)
	{
		//mActorTemplate = actorTemplate;
		mRefedActorTemplate.setRefedEntity (actorTemplate);
	}
	
	public void setZOrder (int zOrder)
	{
		mZOrder = zOrder;
		changePublicPropertyValue (GroupName_ActorGroup, PropertyName_ZOrder, zOrder);
	}
	
	public int getZOrder ()
	{
		return mZOrder;
	}
	
//	public void setFlipX (boolean flipX)
//	{
//		mFlipX = flipX;
//		changePublicPropertyValue (GroupName_ActorGroup, PropertyName_FlipX, flipX);
//	}
	
//	public boolean isFlipX ()
//	{
//		return mFlipX;
//	}
	
//	public void setFlipY (boolean flipY)
//	{
//		mFlipY = flipY;
//		changePublicPropertyValue (GroupName_ActorGroup, PropertyName_FlipY, flipY);
//	}
	
//	public boolean isFlipY ()
//	{
//		return mFlipY;
//	}
	
	public void setAngle (float angle)
	{
		mAngle = angle;
		mRotation = (float) (mAngle * Math.PI / 180.0f);
		
		changePublicPropertyValue (GroupName_ActorGroup, PropertyName_Angle, angle);
	}
	
	public float getAngle ()
	{
		return mAngle;
	}
	
	public double getRotation ()
	{
		return mRotation;
	}
	
	public void setScaleX (float scale)
	{
		mScaleX = scale;
		
		changePublicPropertyValue (GroupName_ActorGroup, PropertyName_ScaleX, scale);
	}
	
	public float getScaleX ()
	{
		return mScaleX;
	}
	
	public void setScaleY (float scale)
	{
		mScaleY = scale;
		
		changePublicPropertyValue (GroupName_ActorGroup, PropertyName_ScaleY, scale);
	}
	
	public float getScaleY ()
	{
		return mScaleY;
	}
	
	public void setSelectedState (int selectedState)
	{
		mSelectedState = selectedState;
	}
	
	public int getSelectedState ()
	{
		return mSelectedState;
	}
	
	public ActorTemplate getActorTemplate ()
	{
		//return mActorTemplate;
		return (ActorTemplate) mRefedActorTemplate.getRefedEntity();
	}
	
	public void attachAppearance (Appearance appearance)
	{
		mAppearanceList.add (appearance);
		addChild (appearance);
	}
	
	public List<Appearance> getAppearanceList ()
	{
		return mAppearanceList;
	}
	
	public int getAppearancesCount ()
	{
		return mAppearanceList.size();
	}
	
	public Appearance getAppearance (int appearanceID)
	{
		return mAppearanceList.get (appearanceID);
	}
	
	public Appearance getAppearance (String appearanceName)
	{
		return (Appearance) getChild (appearanceName);
	}
	
	public void applyActorDefine (ActorDefine actorDefine)
	{
		
	}
	
	public void setPosition (int x, int y)
	{
		setPosX (x);
		setPosY (y);
	}
	
	public void setPosX (int x)
	{
		mPosX = x;
		changePublicPropertyValue (GroupName_ActorGroup, PropertyName_PosX, x);
	}
	
	public void setPosY (int y)
	{
		mPosY = y;
		changePublicPropertyValue (GroupName_ActorGroup, PropertyName_PosY, y);
	}
	
	public int getPosX ()
	{
		return mPosX;
	}
	
	public int getPosY ()
	{
		return mPosY;
	}
	
//	public void render (Graphics g, int posX, int posY, float rotateAngle, float scaleX, float scaleY, int flags)
//	{
//		Graphics2D g2d = (Graphics2D)g;
//	}
//	
//	public void render (Graphics g, int posX, int posY, int scale, int flags)
//	{
//		for (Appearance appearance : mAppearanceList)
//		{
//			appearance.show(g, posX, posY, false, false, scale, flags);
//		}
//	}

	
	
	public List<Property> getCostomPropertyList ()
	{
		List <Property> propertyList = new Vector <Property> ();
		
		PropertyGroupSet propertyGroupSet = getPublicProperties(); 
		
		ActorTemplate actorTemplate = getActorTemplate();
		
		for (PropertyDefineBlock propertyDefineBlock : actorTemplate.getInstancePropertyDefines())
		{
			for (PropertyDefine propertyDefine : propertyDefineBlock.getPropertyDefines())
			{
				propertyList.add (propertyGroupSet.getPropertyInGroup(propertyDefineBlock.getName(), propertyDefine.getName()));
			}
		}
		
		return propertyList;
	}
	
	@Override
	public boolean cloneFrom (EntityObject object)
	{
		logger.assertLog (object != null, "object must not be null");
		logger.assertLog (object.getParent() == getParent (), "Parent must be same.");
		
		if (! super.cloneFrom(object))
			return false;
		
		logger.assertLog (object instanceof Actor, "Only can cloneFrom an Actor object");

		if (! (object instanceof Actor))
			return false;
		
		Actor fromActor = (Actor)object;
		this.setPosX (fromActor.getPosX() + 32);
		
		//
		for (int appearanceID = 0; appearanceID < getAppearancesCount (); ++ appearanceID)
		{
			Appearance fromAppearance = fromActor.getAppearance (appearanceID);
			Appearance appearance     = this.getAppearance (appearanceID);
			
			appearance.cloneFrom (fromAppearance);
		}
		
		return true;
	}
}
